<?php

namespace DataCube\DataCubeAggregation\Functions\Cleaning;

use DataCube\DataCubeAggregation\Exception\CustomException;

class MissingData
{
    // Treating Missing Attribute values as Special values
    public function replaceWith(array $origin, array $target, $replaceBy = null)
    {
        return array_map(function ($element) use ($target, $replaceBy) {
            if (in_array($element, $target)) {
                return $replaceBy; // 标记特定的元素  
            }
            return $element; // 保留原始元素  
        }, $origin);
    }

    /**
     * method:
     *     fix
     *     mean
     *     median
     *     mode
     *     interp : Lagrange
     */
    public function autoFillWith(array $data, $targetKey, array $options = [])
    {
        if (empty($options['method'])) {
            throw new CustomException('Missing fill method on options array');
        }
        $method = $options['method'];
        $limit = !empty($options['limit']) && intval($options['limit']) > 0 ? intval($options['limit']) : 0;
        $limitDirection = !empty($options['limit_direct']) && in_array($options['limit_direct'], ['forward', 'backward']) ? $options['limit_direct'] : 'forward';
        // method
        switch (strtolower($method)) {
            case 'mean':
                # code...
                break;
            case 'median':
                break;
            case 'mode':
                # code...
                break;
            case 'linear':
                # code...
                break;
            case 'lagrange':
                break;
            case 'quadratic':
                # code...
                break;
            case 'hermiter':
                # code...
                break;
            case 'hotdeck':
                # code...
                break;
            case 'fix':
                break;
            case 'ffill':
                break;
            case 'bfill':
                break;
            default:
                # code...
                break;
        }
    }

    /**
     * linear interpolate
     *
     * @param array $inputArray
     * @param array $outputArray
     * @return array
     */
    public function interpolateLinearArray(array $inputArray, array $outputArray)
    {
        $inputCount = count($inputArray);
        $outputCount = count($outputArray);

        // 检查输入和输出数组的长度是否相同  
        if ($inputCount !== $outputCount) {
            throw new CustomException("输入和输出数组的长度必须相同");
        }

        // 遍历数组，对每个缺失值进行插值填充  
        for ($i = 0; $i < $inputCount; $i++) {
            if ($outputArray[$i] === null) {
                // 查找缺失值两侧的已知值  
                $prevIndex = $i - 1;
                $nextIndex = $i + 1;

                // 检查是否存在已知值  
                if ($prevIndex < 0 || $nextIndex >= $inputCount) {
                    throw new CustomException("无法找到缺失值两侧的已知值");
                }

                // 计算插值  
                $prevValue = $inputArray[$prevIndex];
                $nextValue = $inputArray[$nextIndex];
                $prevOutput = $outputArray[$prevIndex];
                $nextOutput = $outputArray[$nextIndex];

                $slope = ($nextOutput - $prevOutput) / ($nextValue - $prevValue);
                $interpolatedValue = $prevOutput + ($slope * ($inputArray[$i] - $prevValue));

                // 填充缺失值  
                $outputArray[$i] = $interpolatedValue;
            }
        }

        return $outputArray;
    }

    /**
     * lagrange
     *
     * @param [type] $x
     * @param [type] $y
     * @param [type] $xValue
     * @return void
     */
    public function lagrangeInterpolation($x, $y, $xValue)
    {
        $n = count($x);

        // 计算基本拉格朗日多项式  
        $result = 0;
        for ($i = 0; $i < $n; $i++) {
            $term = $y[$i];
            for ($j = 0; $j < $n; $j++) {
                if ($j !== $i) {
                    $term *= ($xValue - $x[$j]) / ($x[$i] - $x[$j]);
                }
            }
            $result += $term;
        }

        return $result;
    }

    private function quadraticInterpolation($x, $y, $xValue)
    {
        $n = count($x);

        if ($n !== 3) {
            throw new CustomException("二次插值法需要使用三个已知数据点");
        }

        // 计算二次插值多项式的系数  
        $a = ($y[0] * ($x[1] - $x[2]) + $y[1] * ($x[2] - $x[0]) + $y[2] * ($x[0] - $x[1])) / (($x[0] - $x[1]) * ($x[0] - $x[2]) * ($x[1] - $x[2]));
        $b = ($y[0] - $a * ($x[0] * $x[0])) / $x[0];
        $c = $y[0] - $a * $x[0] * $x[0] - $b * $x[0];

        // 使用二次插值多项式计算估算值  
        $result = $a * $xValue * $xValue + $b * $xValue + $c;

        return $result;
    }

    // Mean/Mode Completer

    // Hot deck imputation
    function hotDeckImputation()
    {
    }
}
